Android OpenGL ES 绘制镜像纹理

在音视频蓬勃发展的今天、加之传统影像和AI的遭遇,在包含手机在内的终端产品上、OpenGL ES技术不可忽缺,习之~

1、背景

只记得有一次面试,面试官提到一个问题,既然你对OpenGL ES有一定的了解,那么可否写一个纹理镜像呢,但是脑子有点懵,对OpenGL ES了解的很初级,并没有回答出来,此篇文章用以记录;

2、基础知识

2.1、坐标系

2.2、GLSL基础语法

2.2.1、变量及变量类型

变量类别 变量类型 描述
void 用于无返回值的函数或空的参数列表
标量 float, int, bool 浮点型,整型,布尔型的标量数据类型
浮点型向量 float, vec2, vec3, vec4 包含1,2,3,4个元素的浮点型向量
整数型向量 int, ivec2, ivec3, ivec4 包含1,2,3,4个元素的整型向量
布尔型向量 bool, bvec2, bvec3, bvec4 包含1,2,3,4个元素的布尔型向量
矩阵 mat2, mat3, mat4 尺寸为2x2,3x3,4x4的浮点型矩阵
纹理句柄 sampler2D, samplerCube 表示2D,立方体纹理的句柄

除上述之外,着色器中还可以将它们构成数组或结构体,以实现更复杂的数据类型。

2.2.2、限定符

限定符 描述
< none: default > 局部可读写变量,或者函数的参数
const 编译时常量,或只读的函数参数
attribute 由应用程序传输给顶点着色器的逐顶点的数据
uniform 在图元处理过程中其值保持不变,由应用程序传输给着色器
varying 由顶点着色器传输给片段着色器中的插值数据

更多语法知识,详见GLSL 详解(基础篇))

2.3、OpenGL ES加载纹理

关于OpenGL ES如果加载纹理,本文不再赘述,如果需要,自行Google

3、关键步骤

接下来主要描述,在OpenGL ES加载纹理的基础上,如何显示镜像纹理;

  • 首先,先将顶点着色器和图元着色器的代码贴上

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # color_vertex.glsl
    attribute vec4 vPosition;
    attribute vec2 vCoordinate;
    uniform mat4 vMatrix;

    varying vec2 aCoordinate;

    void main(){
    gl_Position=vMatrix*vPosition;
    aCoordinate=vCoordinate;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # color_fragment.glsl
    precision mediump float;

    uniform sampler2D vTexture;

    varying vec2 aCoordinate;

    void main(){
    vec4 nColor=texture2D(vTexture, aCoordinate);
    # 此处额外加了一个灰度图显示,可以自行修改
    float c=nColor.r*0.299f + nColor.g*0.587f + nColor.b*0.114f;
    gl_FragColor=vec4(c,c,c,nColor.a);
    }
  • 分析镜像纹理的绘制流程

    首先,在绘制单张纹理的时候,我们会传入四个顶点坐标,四个纹理采样点坐标、分别对应如下四个位置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 顶点坐标
    private static final float[] mVertex = {
    -1.0f, 1.0f,
    -1.0f, -1.0f,
    1.0f, 1.0f,
    1.0f, -1.0f
    };

    // 纹理采样坐标
    private static final float[] mTextureCoord = {
    0.0f, 0.0f,
    0.0f, 1.0f,
    1.0f, 0.0f,
    1.0f, 1.0f,
    };

按照这样的流程,如果要绘制成镜像纹理,我们就需要绘制如下几个点,来完成对称效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  private static final float[] mVertex = {
-1.0f, 1.0f,
-1.0f, -1.0f,
0.0f, 1.0f,
0.0f, -1.0f,
1.0f, 1.0f,
1.0f, -1.0f,
};

private static final float[] mTextureCoord = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 0.0f,
0.0f, 1.0f,
};

关于顶点坐标的绘制就不解释了,比较简单,这块主要由一个关键的概念需要理解,就是GLSL的texture2D的采样率,我们就可以实现如下效果了;

四、其他